#include <ZombieManager.h>

// Constructores y destructores ----------------------------------------

template<> ZombieManager* Ogre::Singleton<ZombieManager>::ms_Singleton = 0;

ZombieManager::ZombieManager(btDiscreteDynamicsWorld* pWorld,
                             Ogre::SceneManager* pSceneManager,
                             Human* pHuman) :
  _pWorld(pWorld), _pSceneManager(pSceneManager), _pHuman(pHuman) {

  Ogre::Entity* pZombieEntity =
    _pSceneManager->createEntity(ZOMBIEMESH);

  // Forma de colisión de los zombis
  BtOgre::StaticMeshToShapeConverter converter1(pZombieEntity);

  _pZombieCollisionShape = converter1.createCylinder();

  // Forma de colisión del jefe
  Ogre::SceneNode* pZombieNode = _pSceneManager->createSceneNode();
  pZombieNode->attachObject(pZombieEntity);
  pZombieNode->setScale(3, 3, 3);

  BtOgre::StaticMeshToShapeConverter converter2(pZombieEntity);

  _pBossCollisionShape = converter2.createCylinder();

  _pSceneManager->destroySceneNode(pZombieNode);
  _pSceneManager->destroyEntity(pZombieEntity);
}

ZombieManager::~ZombieManager() {

  _swarms.clear();
  _zombies.clear();
  delete _pZombieCollisionShape;
}

// Ogre::Singleton -----------------------------------------------------

ZombieManager&
ZombieManager::getSingleton() {

  assert(ms_Singleton);
  return *ms_Singleton;
}

ZombieManager*
ZombieManager::getSingletonPtr() { return ms_Singleton; }

// Factory -------------------------------------------------------------

ZombieSwarm*
ZombieManager::createSwarm(OpenSteer::Vec3 position, int nZombies) {

  ZombieSwarm* pSwarm = new ZombieSwarm(_pWorld,_pSceneManager, position,
                                        this, _pHuman);

  for (int n = 0; n < nZombies; n++) {

    Zombie* pZombie = createZombie(pSwarm->randomPositionInSwarm(),
                                   pSwarm);
    pSwarm->addZombie(pZombie);
  }

  _swarms.push_back(pSwarm);

  return pSwarm;
}

Zombie*
ZombieManager::createZombie(OpenSteer::Vec3 position,
                            ZombieSwarm* pSwarm) {

  Zombie* pZombie = new Zombie(_pWorld, _pZombieCollisionShape,
                               _pSceneManager, position, _pHuman,
                               pSwarm);

  _zombies.push_back(pZombie);

  return pZombie;
}

ZombieSpawner*
ZombieManager::createSpawner(OpenSteer::Vec3 position,
                             int spawnTime,  int maxZombies) {

  ZombieSpawner* pSpawner = new ZombieSpawner(position, this,
                                              _pHuman, spawnTime,
                                              maxZombies);
  _spawners.push_back(pSpawner);

  return pSpawner;
}

Zombie*
ZombieManager::createBoss(OpenSteer::Vec3 position) {

  Zombie* pZombie = new Zombie(_pWorld, _pBossCollisionShape,
                               _pSceneManager, position, _pHuman,
                               NULL, true);

  _zombies.push_back(pZombie);

  return pZombie;

}

// Update --------------------------------------------------------------

void
ZombieManager::update(const float currentTime,
                      const float elapsedTime) {

  updateSwarms(currentTime, elapsedTime);
  updateZombies(currentTime, elapsedTime);
  updateSpawners(currentTime, elapsedTime);
}

void
ZombieManager::updateSwarms(const float currentTime,
                            const float elapsedTime) {

  for (_swarmsIt = _swarms.begin();
       _swarmsIt != _swarms.end();
       _swarmsIt++)
    (*_swarmsIt)->update(currentTime, elapsedTime);
}

void
ZombieManager::updateZombies(const float currentTime,
                             const float elapsedTime) {

  for (_zombiesIt = _zombies.begin();
       _zombiesIt != _zombies.end();
       _zombiesIt++)
    (*_zombiesIt)->update(currentTime, elapsedTime);
}

void
ZombieManager::updateSpawners(const float currentTime,
                              const float elapsedTime) {

  for (_spawnersIt = _spawners.begin();
       _spawnersIt != _spawners.end();
       _spawnersIt++)
    (*_spawnersIt)->update(currentTime, elapsedTime);
}

// Delete --------------------------------------------------------------

void
ZombieManager::deleteZombie(Zombie* pZombie) {

  _zombies.remove(pZombie);
  delete pZombie;
}

void
ZombieManager::deleteSwarm(ZombieSwarm* pZombieSwarm) {

  _swarms.remove(pZombieSwarm);
  delete pZombieSwarm;
}

// void
// ZombieManager::deleteSpawner(ZombieSpawner* pZombieSpawner) {

// }
